﻿    using Luban.Datas;
using Luban.DataVisitors;
using Luban.Defs;
using Luban.Types;
using Luban.Utils;
using NLog;
using System.Text;

namespace Luban.L10N;

/// <summary>
/// 自动文本记录收集访问器
/// 遍历所有数据，收集标记为text的字段，并生成唯一key
/// </summary>
public class AutoTextRecordCollectorVisitor : IDataActionVisitor2<AutoTextRecordContext>
{
    private static readonly Logger s_logger = LogManager.GetCurrentClassLogger();
    
    public static AutoTextRecordCollectorVisitor Ins { get; } = new AutoTextRecordCollectorVisitor();

    public void Accept(DBool data, TType type, AutoTextRecordContext context)
    {
        // 布尔类型不处理
    }

    public void Accept(DByte data, TType type, AutoTextRecordContext context)
    {
        // 字节类型不处理
    }

    public void Accept(DShort data, TType type, AutoTextRecordContext context)
    {
        // 短整型不处理
    }

    public void Accept(DInt data, TType type, AutoTextRecordContext context)
    {
        // 整型不处理
    }

    public void Accept(DLong data, TType type, AutoTextRecordContext context)
    {
        // 长整型不处理
    }

    public void Accept(DFloat data, TType type, AutoTextRecordContext context)
    {
        // 浮点型不处理
    }

    public void Accept(DDouble data, TType type, AutoTextRecordContext context)
    {
        // 双精度浮点型不处理
    }

    public void Accept(DEnum data, TType type, AutoTextRecordContext context)
    {
        // 枚举类型不处理
    }

    public void Accept(DString data, TType type, AutoTextRecordContext context)
    {
        // 只处理标记为text的字符串字段
        if (data != null && type.HasTag("text") && !string.IsNullOrEmpty(data.Value))
        {
            // 生成唯一key：表名_字段名_ID（PascalCase）
            string key = GenerateTextKey(context.Table.Name, context.CurrentFieldPath, context.Record, context);
            
            var recordInfo = new TextRecordInfo
            {
                Key = key,
                OriginalText = data.Value,
                TableName = context.Table.Name,
                FieldName = context.CurrentFieldPath,
                RecordId = GetRecordId(context.Record, context)
            };
            
            context.AddRecord(recordInfo);
            
            s_logger.Debug("收集文本记录 - Key: {}, Text: {}, Table: {}, Field: {}", 
                key, data.Value, context.Table.Name, context.CurrentFieldPath);
        }
    }

    public void Accept(DDateTime data, TType type, AutoTextRecordContext context)
    {
        // 日期时间类型不处理
    }

    public void Accept(DBean data, TType type, AutoTextRecordContext context)
    {
        // 处理Bean类型，递归处理嵌套字段
        if (data != null)
        {
            var beanType = (TBean)type;
            var defBean = beanType.DefBean;
            
            // 保存当前字段路径
            string originalFieldPath = context.CurrentFieldPath;
            
            for (int i = 0; i < data.Fields.Count; i++)
            {
                var field = defBean.HierarchyFields[i];
                var fieldData = data.Fields[i];
                
                if (fieldData != null)
                {
                    // 构建嵌套字段路径
                    string fieldPath = string.IsNullOrEmpty(originalFieldPath) 
                        ? field.Name 
                        : $"{originalFieldPath}.{field.Name}";
                    
                    context.CurrentFieldPath = fieldPath;
                    fieldData.Apply(this, field.CType, context);
                }
            }
            
            // 恢复原始字段路径
            context.CurrentFieldPath = originalFieldPath;
        }
    }

    public void Accept(DArray data, TType type, AutoTextRecordContext context)
    {
        // 处理数组类型
        if (data != null)
        {
            var elementType = ((TArray)type).ElementType;
            
            for (int i = 0; i < data.Datas.Count; i++)
            {
                var elementData = data.Datas[i];
                if (elementData != null)
                {
                    // 保存当前字段路径
                    string originalFieldPath = context.CurrentFieldPath;
                    
                    // 添加数组索引
                    string arrayFieldPath = $"{originalFieldPath}_{i}";
                    context.CurrentFieldPath = arrayFieldPath;
                    
                    elementData.Apply(this, elementType, context);
                    
                    // 恢复原始字段路径
                    context.CurrentFieldPath = originalFieldPath;
                }
            }
        }
    }

    public void Accept(DList data, TType type, AutoTextRecordContext context)
    {
        // 处理列表类型
        if (data != null)
        {
            var elementType = ((TList)type).ElementType;
            
            for (int i = 0; i < data.Datas.Count; i++)
            {
                var elementData = data.Datas[i];
                if (elementData != null)
                {
                    // 保存当前字段路径
                    string originalFieldPath = context.CurrentFieldPath;
                    
                    // 添加列表索引
                    string listFieldPath = $"{originalFieldPath}_{i}";
                    context.CurrentFieldPath = listFieldPath;
                    
                    elementData.Apply(this, elementType, context);
                    
                    // 恢复原始字段路径
                    context.CurrentFieldPath = originalFieldPath;
                }
            }
        }
    }

    public void Accept(DSet data, TType type, AutoTextRecordContext context)
    {
        // 处理集合类型
        if (data != null)
        { 
            var elementType = ((TSet)type).ElementType;
            
            int index = 0;
            foreach (var elementData in data.Datas)
            {
                if (elementData != null)
                {
                    // 保存当前字段路径
                    string originalFieldPath = context.CurrentFieldPath;
                    
                    // 添加集合索引
                    string setFieldPath = $"{originalFieldPath}_{index}";
                    context.CurrentFieldPath = setFieldPath;
                    
                    elementData.Apply(this, elementType, context);
                    
                    // 恢复原始字段路径
                    context.CurrentFieldPath = originalFieldPath;
                    index++;
                }
            }
        }
    }

    public void Accept(DMap data, TType type, AutoTextRecordContext context)
    {
        // 处理映射类型
        if (data != null)
        {
            var mapType = (TMap)type;
            var keyType = mapType.KeyType;
            var valueType = mapType.ValueType;
            
            foreach (var kv in data.DataMap)
            {
                var keyData = kv.Key;
                var valueData = kv.Value;
                s_logger.Info($"处理映射键值对：{kv.Key} -> {kv.Value}");
                // 分开处理键值对
                if (keyData != null)
                {
                    // 保存当前字段路径
                    string originalFieldPath = context.CurrentFieldPath;
                    
                    // 获取键的字符串表示
                    string keyStr = GetKeyString(keyData, keyType);
                    string mapFieldPath = $"{originalFieldPath}_KEY";
                    context.CurrentFieldPath = mapFieldPath;
                    
                    keyData.Apply(this, keyType, context);
                    
                    // 恢复原始字段路径
                    context.CurrentFieldPath = originalFieldPath;
                }
                if (valueData != null)
                {
                    // 保存当前字段路径
                    string originalFieldPath = context.CurrentFieldPath;
                    
                    // 获取值的字符串表示
                    string valueStr = GetKeyString(valueData, valueType);
                    string mapFieldPath = $"{originalFieldPath}_VALUE";
                    context.CurrentFieldPath = mapFieldPath;
                    
                    valueData.Apply(this, valueType, context);
                    
                    // 恢复原始字段路径
                    context.CurrentFieldPath = originalFieldPath;
                }
            }
        }
    }
    
    /// <summary>
    /// 生成文本键：表名_字段名_ID（PascalCase）
    /// </summary>
    private string GenerateTextKey(string tableName, string fieldPath, Record record, AutoTextRecordContext context)
    {
        // 获取记录ID
        string recordId = GetRecordId(record, context);
        
        // 清理字段路径中的数组索引等
        string cleanFieldPath = fieldPath;
        
        // 转换为PascalCase
        string pascalTableName = ToUpper(tableName);
        string pascalFieldPath = ToUpper(cleanFieldPath.Replace('.', '_'));
        string pascalRecordId = ToUpper(recordId);
        
        return $"{pascalTableName}_{pascalRecordId}_{pascalFieldPath}";
    }
    
    /// <summary>
    /// 清理字段路径，移除数组索引等
    /// </summary>
    private string CleanFieldPath(string fieldPath)
    {
        if (string.IsNullOrEmpty(fieldPath))
            return "";
            
        // 移除数组索引，如field[0] -> field
        var cleaned = System.Text.RegularExpressions.Regex.Replace(fieldPath, @"\[[^\]]*\]", "");
        return cleaned;
    }
    
    /// <summary>
    /// 转换为全大写，AA_BB_CC
    /// </summary>
    private string ToUpper(string input)
    {
        if (string.IsNullOrEmpty(input))
            return "";
            
        // 转化为大写，不要去掉特殊符号
        return input.ToUpper();
    }
    
    /// <summary>
    /// 获取记录ID
    /// </summary>
    private string GetRecordId(Record record, AutoTextRecordContext context)
    {
        if (record == null)
            return "Unknown";
            
        // 如果没有表上下文，使用行号
        if (context?.Table == null)
            return $"Row{record.AutoIndex}";
            
        // 尝试获取主键字段
        var keyField = context.Table.IndexField;
        if (keyField != null)
        {
            var keyData = record.Data.GetField(keyField.Name);
            if (keyData != null)
            {
                return keyData.ToString();
            }
        }
        
        // 如果没有主键，使用行号或其他唯一标识
        return $"Row{record.AutoIndex}";
    }
    
    /// <summary>
    /// 获取键的字符串表示
    /// </summary>
    private string GetKeyString(DType keyData, TType keyType)
    {
        if (keyData is DString dString)
        {
            return dString.Value;
        }
        else if (keyData is DInt dInt)
        {
            return dInt.Value.ToString();
        }
        else if (keyData is DLong dLong)
        {
            return dLong.Value.ToString();
        }
        else if (keyData is DEnum dEnum)
        {
            return dEnum.Value.ToString();
        }
        
        return keyData.ToString();
    }
}
